import channels_graphql_ws
import graphene

from graphql import GraphQLError
from objektoj.models import Objekto, ObjektoPosedanto
from objektoj.api.schema import ObjektoNode
from universo_bazo.models import Realeco
from universo_uzantoj_websocket.models import UniversoUzantojWebsocket


# Реализация подписки для изменения по пользователю:
# - изменение нахождние управляемого объекта в подписной реальности
# - изменение финансов в реальности

# Подписки для WebSocket на действия в кубе
class UzantoEventoj(channels_graphql_ws.Subscription):
    """Подписка на действия в реальности"""
    evento = graphene.String(required=True)
    objekto = graphene.relay.node.Field(ObjektoNode)

    class Arguments:
        """Тут аргументы, передающиеся для подписки на события в реальности"""
        # ID куба
        realeco = graphene.Int(required=True)

    def subscribe(self, info, realeco):
        """В этом методе определяется реальность для подписки на действия в ней"""
        uzanto = info.context.user
        if uzanto.is_authenticated:
            # просмотр разрешен всем зарегестрированным пользователям
            # реальность
            try:
                realeco_table = Realeco.objects.get(id=realeco, forigo=False,
                                                    arkivo=False, publikigo=True)
            except Realeco.DoesNotExist:
                raise GraphQLError(
                    'Невозможно отслеживать реальность c ID {}, она не сущствуют или не доступна'.format(
                        realeco
                    )
                )

            # записываем информацию об установки подписки
            try:
                uzanto_websocket = UniversoUzantojWebsocket.objects.get(
                    posedanto = uzanto
                )
            except UniversoUzantojWebsocket.DoesNotExist:
                uzanto_websocket = UniversoUzantojWebsocket.objects.create(
                    posedanto = uzanto,
                )
            uzanto_websocket.realeco = realeco_table
            uzanto_websocket.subscription_uzanto = True
            uzanto_websocket.save()
            lll = ['Realeco_{}'.format(realeco),]
            return lll or None

        raise GraphQLError('Необходима авторизация')

    @staticmethod
    def publish(payload, info, realeco):
        """ публикация изминений в реальности """
        evento = payload.get('evento')

        objekto = None
        try:
            if  evento == 'objekto_uzanto': # изменение управляемого объекта в кубе
                objekto = Objekto.objects.get(
                    uuid=payload.get('objekto'),
                    publikigo=True,
                    arkivo=False,
                    forigo=False
                )
            # рассылаем только владельцу объекта
            # находим владельца объекта
            posedanto_masivo = ObjektoPosedanto.objects.filter(objekto=objekto, 
                forigo=False,
                arkivo=False, 
                publikigo=True
            )
            posedanto_set = set(
                posedanto_masivo.values_list('posedanto_uzanto__id', flat=True)
            )
            print('== posedanto_set == ', posedanto_set)
            for posedanto in posedanto_masivo:
                # отправляем только владельцам объекта
                if info.context.user == posedanto.posedanto_uzanto:
                    return UzantoEventoj(evento=evento, objekto=objekto)
        except Objekto.DoesNotExist:
            pass

        return UzantoEventoj.SKIP

    @classmethod
    def objekto_uzanto(cls, objekto, realeco):
        """Этот метод должен вызываться при изминении управляемого объекта в соответствующей реальности."""
        group='Realeco_{}'.format(realeco.id)
        payload={
            'evento': 'objekto_uzanto',
            'realeco': str(realeco.uuid),
            'objekto': str(objekto.uuid),
        }
        cls.broadcast(
            group=group,
            payload=payload
        )


class UzantoWSSubscription(graphene.ObjectType):
    uzanto_eventoj = UzantoEventoj.Field()
